package jmine.tec.persist.subscription;

import jmine.tec.subscription.Publication;
import jmine.tec.subscription.SubscriptionSettings;
import jmine.tec.subscription.impl.AbstractPublisher;
import jmine.tec.subscription.impl.SubscriptionManagerImpl;

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

/**
 * Versao de {@link AbstractPublisher} que abre uma nova transacao antes de chamar o metodo {@link #newPublication(SubscriptionSettings)}
 * 
 * @author takeshi
 * @param <P> a Publication
 */
public abstract class AbstractTransactedPublisher<P extends Publication> extends AbstractPublisher<P> {

    private PlatformTransactionManager transactionManager;

    private static final TransactionDefinition DEFAULT_TX_DEFINITION = SubscriptionManagerImpl.DEFAULT_TX_DEFINITION;

    /**
     * @param publicationType {@link Class}
     */
    public AbstractTransactedPublisher(Class<P> publicationType) {
        super(publicationType);
    }

    /**
     * {@inheritDoc}
     */
    public final P newPublication(SubscriptionSettings settings) {
        TransactionStatus tx = this.transactionManager.getTransaction(DEFAULT_TX_DEFINITION);
        boolean commit = false;
        try {
            final P p = this.newPublicationTransacted(settings);
            commit = true;
            return p;
        } finally {
            if (commit) {
                this.transactionManager.commit(tx);
            } else {
                this.transactionManager.rollback(tx);
            }
        }
    }

    /**
     * Metodo a ser sobrescrito nas subclasses. Deve fazer o que deveria fazer o {@link #newPublication(SubscriptionSettings)}
     * 
     * @param settings o {@link SubscriptionSettings}
     * @return P
     */
    protected abstract P newPublicationTransacted(SubscriptionSettings settings);

    /**
     * @param transactionManager the transactionManager to set
     */
    public void setTransactionManager(PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

}
